function JApplication(doc)
{
	var self = this,
	_version = appVersion,
	_QIVersion = appQIVersion,
	_doc = doc,
	_forms = [],
	_objects = [],
	_clipboard = null,
	_disposing = false,
	_disposed = false,
	_loggingOut = false,

	_localized = new JDataset(this, '', '__localized', 'id', '', dfNone),
	_appDS = new JDataset(this, '', '__helperDS', '', '', dfNone),

	_cgiPath = appCgiPath,
	_pingLast = null,
	_pingTimer = null,
	_debugTiming = new FastString(),
	_debugEnabled = false,
	_debugStartTime = new Date(),
	_formSelector = null,
	_cleaning = false,
	_splashCnt = 0,
	_popups = [],
	_sepResizer = null,
	_toolbarHTML = '',

	_isPortalVersion = false,
	_portalUserID = '',
	_portalFuncID = null,
	_portalFuncParams = null;

	this.schema   = fmSchema;
	this.activeForm = null;
	this.imageDir = appImageDir;
	this.images = [];
	this.lastImg = null;
	this.session = "";
	this.toolbar = null;
	this.pingInterval = appPingInterval;

	this.$ = $;
	this.addImage = addImage;
	this.askForSaving = askForSaving;
	this.recalcSize = _windowResize;
	this.canPerformAction = canPerformAction; 
	this.cgiPath = cgiPath;
	this.setCgiPath = setCgiPath;
	this.dispose = dispose;
	this.findDialog = findDialog;
	this.fillFormsList = fillFormsList;
	this.getFormList = getFormList;
	this.getDocument = getDocument;
	this.getObject = getObject;
	this.getPreviousForm = getPreviousForm;
	this.getTempDiv = getTempDiv;
	this.getWindow = getWindow;
	this.hidePopups = hidePopups;
	this.isCleaning = isCleaning;
	this.isDebugEnabled = function() { return _debugEnabled; };
	this.isDisposing = 	function() { return _disposing;	};

	this.isPortalVersion = isPortalVersion;
	this.loginPortalUser = loginPortalUser;
	this.setPortalFunctionCode = setPortalFunctionCode;
	this.callPortalFunction = callPortalFunction; 

	this.onformcreated = new JEvent();

	this.localize = localize;
	this.login = login;
	this.logout = logout;
	this.makeAjaxCall = makeAjaxCall;
	this.messageBox = messageBox;
	this.openRichTextForm = openRichTextForm;
	this.performAction = performAction;
	this.ping = ping;
	this.post = post;
	this.registerPopup = registerPopup;
	this.registerObject = registerObject;
	this.unregisterObject = unregisterObject;
	this.refresh = refresh;
	this.load = load;
	this.splash = splash;
	this.setSplashInfo = setSplashInfo;
	this.selectForm = selectForm;
	this.setFilter = setFilter;
	this.setSorting = setSorting;
	this.set_activeForm = set_activeForm;
	this.set_QIVersion = set_QIVersion; 
	this._debugAdd = debugAdd;
	this._debugClear = debugClear;
	this._debugShow = debugShow;
	this._pingResult = _pingResult;

	this.onlogin = new JEvent();
	this.onbeforelogout = new JEvent();
	this.onresize = new JEvent();
	
	AddEventHandler();

	_localized.addField(new JField('id', '', ftString, '', ffNone));
	_localized.addField(new JField('text', '', ftString, '', ffNone));
	registerObject("localized", _localized);

	_appDS.addField(new JField('__forms', '', ftString, '', ffNone));
	registerObject('appDS', _appDS);

	_clipboard = new JClipboard(self);

	this.onlogin.attach(afterLogin);
	
	function __keyDown(e) {
		if ((e.returnValue != false) &&((e.target == document.body) || (e.target == null))) {
			if (self.activeForm && self.activeForm.activeControl && (self.activeForm.activeControl instanceof JGrid)){
				self.activeForm.activeControl.onKeyDown(e);
			}
			
			
		}
	}
	
	function AddEventHandler () {
		if (document.addEventListener) {   // all browsers except IE before version 9
			document.addEventListener ("keydown", __keyDown, false);
		} 
		else {
			if (document.attachEvent) {    // IE before version 9
				document.attachEvent ('onkeydown', __keyDown);
			}
		}
	}

	function RemoveEventHandler () {
		if (document.removeEventListener) {    // all browsers except IE before version 9
			document.removeEventListener ("keydown", __keyDown, false);
		}
		else {
			if (document.detachEvent) {        // IE before version 9
				document.detachEvent ('onkeydown', __keyDown);
			}
		}
	}

	function $(id)
	{
		if (_doc.getElementById)
			return _doc.getElementById(id);

		if (_doc.all)
			return _doc.all[id];

		return null;
	}

	function askForSaving(caller, msg)
	{
		if (utils.isEmpty(msg))
			msg = self.localize("msgSaveChanges");

		if ((self.isDisposing()) && (caller != null))
		{
			var formName;
			if (caller.isForm)
			{
				formName = caller.caption;
			}
			else
			{
				formName = caller.parent;
				if (getObject(caller.parent) != null)
					formName = getObject(caller.parent).caption;
			}

			msg += ' (Form: ' + formName + ')'; 
		}

		if (window.confirm(msg))
			return true;

		return false;
	}

	function addImage(name, src, type, path)
	{
		self.images[name] = new Image();
		if ((type == null) && (path == null))
		{
			self.images[name].src = src;
		}
		else
		{
			self.images[name].src = (path || (utils.format(self.imageDir, type) + src));
		}
		self.images.length++;
	}

	function cgiPath()
	{
		return _cgiPath;
	}

	function setCgiPath(path)
	{
		_cgiPath = path;
	} 

	function afterLogin()
	{
		self.toolbar = getObject('mainbar');
		if (self.toolbar == null)
			self.toolbar = new JToolbar(self, '', 'mainbar');

		var fs = new FastString();
		self.toolbar.render(fs);
		var toolbarHTML = fs.toString();

		if (_toolbarHTML != toolbarHTML)
		{
			_toolbarHTML = toolbarHTML;
			$(idNavigation).innerHTML = _toolbarHTML;
			self.toolbar.load();
	
			_formSelector = new JEnumPicker(self, null, idFormSelector + '_selector', _appDS, '__forms', /*'65;3;150;20'*/ ';;150;20', null);
			_formSelector.onchange.attach(selectForm);
			$(idFormSelector).innerHTML = _formSelector.render();
			_formSelector.load();
			_formSelector.canRollQuery = canPerformAction;
		}

		_windowResize();
		_removeForm(null);

		utils.attachEvent(getWindow(), 'resize', _windowResize);
		utils.attachEvent(getDocument(), 'click', hidePopups);
	}

	function _windowResize()
	{
		//var h = $(idRightPane).offsetHeight - $(idNavigation).offsetHeight - 8;
		var formBox = utils.getElementBox($('app_form'));
		var h = document.body.clientHeight - formBox.y  - 8;
		if (h > 0)
		{
			var elem = $(idLeftPane);
			elem.style.height = h + 'px';

			elem = $(idRightPane);
			elem.style.height = h + 'px';

			elem = $(idMain);
			elem.style.height = (h - $(idNavigation).offsetHeight) + 'px';

			elem = $(idTree);
			var newH = h - $(idLogo).offsetHeight;
			if (elem.scrollHeight > newH);
				newH -= 14;
			elem.style.height = newH + 'px';

			elem = $(idMenuSep);
			elem.style.height = h + 'px';

			self.onresize.raise(self);
		}
	}


	function hidePopups()
	{
		var items = _popups.length;
		if (items == 0)
			return;

		for (var i = 0; i < items; i++)
		{
			var elem = $(_popups.pop());
			if (elem != null)
				elem.style.display = 'none'
		}
	}

	function closeForms()
	{
		_forms.forEachRev(function(form)
		{
			if (form == null)
				return;


			if (form.close)
				form.close(null, true);

			self.unregisterObject(form.name);

		}, self);
	}

	function fillFormsList(rolling)
	{
		if ((!rolling) || (_formSelector == null))
			return;

		var list = new Array();
		_forms.forEach(function(form, i)
		{
		        if (utils.isEmpty(form.nextModal))
				list.push(i.toString() + '=' + form.caption);
		}, self);

		var fld = _appDS.fields['__forms'];
		fld.setItems(list);

		_formSelector.refreshPicker();

		_formSelector.select(_forms.length - 1);
	}

	function isPortalVersion()
	{
		return _isPortalVersion;
	}

	function setPortalFunctionCode(funcID, funcParams)
	{
		_portalFuncID = funcID;
		_portalFuncParams = null;
		if (funcParams)
			_portalFuncParams = funcParams;
	}

	function callPortalFunction(functionID, functionParams)
	{
		if (utils.isEmpty(functionID))
			return; 

		query = new Postback(raCallPFunc);
		query.set('fid', functionID);

		if ((! (utils.isEmpty(functionParams))) && (functionParams != 'undefined'))
		{
//			query.append(functionParams);
			query.set('fparams', functionParams);
		}

		post(query);
	}

	function selectForm(index)
	{
		if ((index == null) || (index < 0))
			return;

		if (typeof index == 'string')
			index = parseInt(index);

		var form = _forms[index];
		if (self.activeForm === form)
			return;

		self.activeForm.set_visible(false);

		_forms.removeAt(index);
		_forms.push(form);

		self.activeForm = form;
		form.set_visible(true);

		fillFormsList(true);
	}

	function set_activeForm(formName)
	{
		for (var i = 0; i < _forms.length; i++)
		{
			if (_forms[i].name == formName)
			{
				selectForm(i);
				break;
			}
		}
	}

	function set_QIVersion(version)
	{
		if ((! _isPortalVersion) && (version != _QIVersion) && (_QIVersion != ''))
			alert('Incorrect QI version!\nQI: ' + version + '\nIC: ' + _QIVersion);
	}

	function getFormList()
	{
		var list = new Array();
		_forms.forEach(function(form)
		{
			list.push(form.name);
		}, self);

		return (list.join(scItemSep));
	}

	function getDocument()
	{
		return _doc;
	}

	function getObject(name)
	{
		return _objects[name];
	}

	function getPreviousForm(form)
	{
		if (form == null)
			form = self.activeForm;

		var idx = _forms.indexOf(form);
		if (idx > 0)
			return _forms[idx - 1];

		return null;
	}

	function getTempDiv()
	{
		var tempDiv = $('__tempDiv');
		if (tempDiv == null)
		{
			tempDiv = _doc.createElement('div');
			tempDiv.id = '__tempDiv';
			tempDiv.style.visibility = 'hidden';
		}

		return tempDiv;
	}

	function getWindow()
	{
		if (_doc == null)
			return window;

		if (_doc.defaultView)
			return _doc.defaultView;
		else
		if (_doc.parentWindow)
			return _doc.parentWindow;

		return window;
	}

	function registerPopup(id, hidePrev, event)
	{
		if (hidePrev == true)
			hidePopups();

		utils.cancelEvent(event);

		_popups.push(id);
	}

	function registerObject(name, object)
	{
		_objects[name] = object;
		_objects.length++;

		if (object.constructor == JForm)
		{
			var prevFrm = self.activeForm;
			if ((prevFrm == null) || (prevFrm.name == object.name))
			{
				prevFrm = getPreviousForm(object);
				if ((prevFrm == null) && (_forms.length > 0))
					prevFrm = _forms[_forms.length - 1];
			}

			if (prevFrm != null)
				prevFrm.set_visible(false);

			_forms.push(object);
			fillFormsList(true);
		}

		return object;
	}

	function unregisterObject(name)
	{
		if (utils.isEmpty(name))
			return;

		var obj = name;
		if (typeof(name) == 'string')
			obj = _objects[name];

		if (obj != null )
		{
			if (obj.isForm)
				_removeForm(obj);
			else
			{
				delete _objects[obj.name];
				if (_objects.length > 0)
					_objects.length--;
			}
		}
	}

	function _removeForm(form, noActiveSet)
	{
		if (_forms == null)
			return;

		if (form != null)
		{
			var formName = form.name;
			var prevForm = form.previous;
			_forms.remove(form);
			delete _objects[form.name];
			if (_objects.length > 0)
				_objects.length--;
	
			if (form.dispose)
				form.dispose();
	
			if (!_cleaning)
			{
				_forms.forEachRev(function(frm, i)
				{
					if (frm == null)
						return;
	
					if ((frm.previous == formName) && (frm.modal == 'prev'))
					{
						_removeForm(frm, true);
					}
				}, self);
	
				if (!noActiveSet)
				{
					if (self.activeForm == form)
					{
						self.activeForm = null;
						if (!utils.isEmpty(prevForm))
							self.activeForm = self.getObject(prevForm);

						if (self.activeForm == null)
							self.activeForm = _forms[_forms.length - 1];

						if ((self.activeForm != null) && (self.activeForm.set_visible))
							self.activeForm.set_visible(true);
					}

					fillFormsList(true);
				}
			}

			if ((_forms.length == 0) && (_isPortalVersion))
			{
				self.logout(true);
				window.ICApp = null;
				window.setTimeout("window.close()", 1000);
				return;
			} 
		}

		if ((_forms.length == 0) && (self.toolbar != null))
		{
			var tb = self.toolbar;
			tb.setFiltering(false);
			tb.setRefresh(false);
			tb.setSearching(false);
			tb.setSorting(false);
			tb.setSave(false);
			tb.setPrinting(false);
			tb.setRecordOperations(false);
		}

	}

	function localize(id, _default)
	{
		var row = _localized.findByKey(id);
		return ((row != null) ? _localized.getText("text", row) : utils.coalesce(_default, '*' + id + '*'));
	}

	function login(userName, password)
	{
		_loggingOut = false;
		splash(true);
		window.setTimeout(function(){_dologin(userName, password)}, 50);
	}

	function loginPortalUser(userName, password, portalUserID, funcID, funcParams)
	{
		_isPortalVersion = true;
		if (_cgiPath == appCgiPath)
			_cgiPath = portalCgiPath;

		_portalUserID = portalUserID;

		if (funcID)
			_portalFuncID = funcID;
			
		if (funcParams)
			_portalFuncParams = funcParams;
		
		if (! utils.isEmpty(userName))
		{
			login(userName, password);
		}
	}

	function _dologin(userName, password)
	{
			var query;
			if ((utils.isEmpty(userName)) && ($('uid') != null))
				userName = escape($('uid').value);
			if ((utils.isEmpty(password)) && ($('pwd') != null))
				password = escape($('pwd').value);

			query = 'act=login&uid=' + (userName || '') + '&pwd=' + (password || '') + '&btn=Login';

			if (_isPortalVersion)
				query += '&portal=1'

			makeAjaxCall("post", _cgiPath, query, null, true, _loginResult, 600000);
	}

	function _loginResult(resultStatus, result)
	{
		try
		{
			if ((resultStatus != 200) && (resultStatus != 201))
			{
				showError('Type=4\nText=Chyba při komunikaci se serverem!\nAn error occurred during the communication with the server!\n\nStatus: ' + resultStatus);
			}

			if (utils.isEmpty(result)) 
			{
				return;
			}

			var lPart = $(idLeftPane);
			var rPart = $(idRightPane);
			var sep = $(idMenuSep);

			if ((lPart != null) && (rPart != null) && (sep != null))
			{
				_sepResizer = new JResizer(self, sep, lPart, rPart);
				_sepResizer.onresize.attach(_windowResize);

				lPart.style.left = 0;
				lPart.style.width = '20%';

				sep.style.left = lPart.style.width;

				rPart.style.left = '20%';
				rPart.style.width = '79%';
			}

			setSplashInfo('processing...');
			process(result);

			if (utils.isEmpty(self.session))
				logout();
			else
			{
				if ($(idLoginForm))
					$(idLoginForm).style.display = 'none';
				$(idAppForm).style.display = 'block';

				self.onlogin.raise(self);
				_pingTimer = window.setTimeout(self.ping, self.pingInterval);
			}

		}
		catch (ex)
		{
		    if (_debugEnabled)
			  debugger;

		    var msg = ex.message;
		}
		finally
		{
			splash(false);
		}
		
		if (self.isPortalVersion())
		{
			callPortalFunction(_portalFuncID, _portalFuncParams);
		}
	}


	function logout(sync)
	{
		if (_loggingOut)
			return

		_loggingOut = true;
		self.onbeforelogout.raise(self);

		if (_pingTimer != null)
			window.clearTimeout(_pingTimer);

		utils.detachEvent(getWindow(), 'resize', _windowResize);

		var session = self.session
		    query = '', 
		    result = null;

		hidePopups();
		utils.detachEvent(getDocument(), 'click', hidePopups);

		_cleanup();		// make cleanup first as some objects may save some data...
		fillFormsList(true);

		if (! utils.isEmpty(session))
		{
			query = 'act=logout&cid=' + session;
			if (sync)
				result = makeAjaxCall("post", _cgiPath, query, null, false);
			else
				result = makeAjaxCall("post", _cgiPath, query, null, true);

			$(idAppForm).style.display = 'none';
			if ($(idLoginForm))
			{
				$(idLoginForm).style.display = 'block';
				$('pwd').value = '';
				$('uid').value = '';
				window.setTimeout(function() { $('uid').focus(); }, 200);
			}
		}

		if (_sepResizer != null)
		{
			if (_sepResizer.onresize != null)
				_sepResizer.onresize.detach(_windowResize);
			_sepResizer.dispose();
			_sepResizer = null;
		}
	}

	function _cleanup()
	{
		if ((_cleaning) || (_disposed))
			return;

		_cleaning = true;

		closeForms();

		self.activeForm = null;
		_forms = [];

		utils.purgeHTML(_objects['tvwm1']);
		if ((_objects['tvwm1'] != null) && (_objects['tvwm1'].dispose))
			_objects['tvwm1'].dispose();

		delete _objects['tvwm1'];

		_objects = [];
		_localized.clear(true);
		_appDS.clear(true);
		registerObject("localized", _localized);
		registerObject('appDS', _appDS);

		if ($(idTree))
			$(idTree).innerHTML = '';

		splash(false);

		self.session = "";
		_cleaning = false;
	}

	function ping()
	{
		if (self.session == '')
			return;

		var query = 'act=ping&cid=' + self.session;
		makeAjaxCall("post", _cgiPath, query, null, true, self._pingResult, 20000);
	}

	function _pingResult(resultStatus, pingResult)
	{
		if ((resultStatus == 200) || (resultStatus == 201))
		{
			_pingLast = new Date();
			_pingTimer = window.setTimeout(self.ping, self.pingInterval);
			process(pingResult, true);
		}
		else
		{
/*
			if (resultStatus == 500)
			{
				// TODO: inform user  that there is no connection - once per every dropout
				//      pingResult = '<user cmd="nosession" />';
			}
*/
			_pingTimer = window.setTimeout(self.ping, 5000);	// retry in 5 seconds
		}
	}

	function findDialog()
	{
		var findDlg = new JFindDialog(self, '', 'finddlg', self.localize('capFindDialog'), raSetSort, 'POST', '0;0;350;170', self.activeForm.name);
		self.registerObject('finddlg', findDlg);
		self.refresh(idMain);
	} 

	function setFilter(switchOn)
	{
		if (switchOn)
			post(raOpenFilter, null);
		else
			post(raResetFilter, null);
	}

	function setSorting()
	{
		var sortDialog = new JSortDialog(self, '', 'sortdlg', self.localize('capSortDialog'), raSetSort, 'POST', '0;0;400;300', self.activeForm.name);
		self.registerObject('sortdlg', sortDialog);
		self.refresh(idMain);
	}

	function reportDialog()
	{
		var reportDlg = new JReportDialog(self, '', 'reportdlg', self.localize('capReportDialog'), raPrintReport, 'POST', '0;0;350;170', self.activeForm.name);
		self.registerObject('reportdlg', reportDlg);
		self.refresh(idMain);
	} 

	function messageBox(type, message, buttons, actions)
	{
		var mBox = new JMessageDialog(self, '', 'msgBox', type, message, button, actions, '0;0;400;300');
		self.registerObject('msgBox', mBox);
		self.refresh(idMain);
	}

	function makeAjaxCall(postGet, strURL, strSubmit, encType, async, resultFunc, timeout)
	{
		var splashInfo = getSplashInfo();
		setSplashInfo('loading...');
		var result = utils.ajaxCall(postGet, strURL, strSubmit, encType, async, resultFunc, timeout);
		setSplashInfo(splashInfo);
		return result;
	}

	function openRichTextForm(url)
	{
		//alert('openForm called: ' + url);

		var query = new Postback(raOpenRichTextForm);
		query.set('url', url);
		self.post(raOpenRichTextForm, query);
	}

	function post(action, data, noProcess, async, resultFunc)
	{
		if (self.session == '')
			return;

		if ((action.constructor == Postback) && (data == null))
		{
			data = action;
			action = data.action;
		}
		else
		if ((action == null) && (data != null))
			action = data.action;

		var query  = new Postback(action),
			afmobj = self.activeForm,
			pfmobj = dset = pdset = null;

		query.append(data);
		query.set('act', raActionNames[action]);
		query.set('cid', self.session);
		query.set('tgt', self.name);

		var fml = self.getFormList();
		query.set('fml', fml);

		if ((_isPortalVersion) && (! utils.isEmpty(_portalUserID)))
		{
			query.set('uid', _portalUserID);
		}

		if (afmobj != null)
		{
			if (afmobj.activeControl != null)
				query.set('acl', afmobj.activeControl.name);
			
			if ((afmobj.activeControl != null) && (afmobj.activeControl.dataset != null))
				dset = afmobj.activeControl.dataset;
			else
				dset = afmobj.dataset; 

			if (query.get('afm') == null)
			{
				query.set('afm', afmobj.name);
				if (afmobj.previous != null)
					pfmobj = self.getObject(afmobj.previous);
			}

			if ((dset != null) && (!dset.isDisposed()))
			{ 
				if (query.get('ads') == null)
					query.set('ads', dset.name);

				if (query.get('rec') == null)
					query.set('rec', (dset.getCurrentRecord() != null) ? dset.getCurrentRecord().key : '');

				if ((query.get('sel') == null) && (dset.recordSelector != null))
					query.set('sel', dset.recordSelector.toString());
			}

			if (afmobj.datasets != null)
			{
				var dsName = query.get('ads'); 
				afmobj.datasets.forEach(function(dataset)
				{
					if ((dataset == null) || (dataset.isDisposed()) || (dataset.name == dsName)) 
						return;

					var cRec = dataset.getCurrentRecord();
					if ((cRec == null) || (! utils.inList(cRec.getState(), rsModified, rsAdded)))
						return;
					
					query.set('rec_' + dataset.name, (cRec != null) ? cRec.key : '')
					query.set('dat_' + dataset.name, (cRec != null) ? escape(cRec.toString()) : '');

				}, self)
			}

			if (afmobj.$$('_content') != null)
			{
				query.set('scr_width', afmobj.$$('_content').clientWidth);
				query.set('scr_height', afmobj.$$('_content').clientHeight);
			}
		}
		else
		if ((utils.isEmpty(fml)) && ($(idMain) != null))
		{
			query.set('scr_width', $(idMain).clientWidth - 158);
			query.set('scr_height', $(idMain).clientHeight - 40);
		}

		if (pfmobj != null)
		{
			if ((pfmobj.activeControl != null) && (pfmobj.activeControl.dataset != null))
				pdset = pfmobj.activeControl.dataset;
			else
				pdset = pfmobj.dataset;

			if (query.get('pfm') == null)
				query.set('pfm', pfmobj.name);

			if ((query.get('pds') == null) && (pdset != null))
				query.set('pds', pdset.name);
		}

		if ((dset != null) && (utils.inList(action, raCleanup)) && (dset.getRecCount() > 0))
		{
			dset.saveAll(true);
			if (utils.isEmpty(query.get('rec')))
				query.set('rec', dset.getCurrentRecord().key);
			query.set('page', dset.pageNo);
		}

		if (utils.inList(action, raPrint, raPrintSelected))
		{
			query.set('rec', ((action == raPrintSelected) && (dset.getCurrentRecord() != null)) ? dset.getCurrentRecord().key : '');
			query.set('act', 'print');

			if (self.isPortalVersion())
				window.open(_cgiPath + '&' + query.getQuery(), 'dcc');
			else
				window.open(_cgiPath + '?' + query.getQuery(), 'dcc');

		}
		else
		if (action == raPrintReport)
		{
			query.set('act', 'report');
			if (query.get('pfm') == null)
				query.set('pfm', pfmobj.name);
			if (query.get('pds') == null)
				query.set('pds', pdset.name);
			if (query.get('rec') == null)
				query.set('rec', (pdset.getRecCount() > 0) ? pdset.getCurrentRecord().key : '');
			if ((query.get('psel') == null) && (pdset != null) && (pdset.recordSelector != null))
			{
				query.set('psel', pdset.recordSelector.toString());
			}

			if (self.isPortalVersion())
				window.open(_cgiPath + '&' + query.getQuery(), 'dcc');
			else
				window.open(_cgiPath + '?' + query.getQuery(), 'dcc');
		}
		else
		{
			if (query.get('pfm') == '%')
				query.set('pfm', pfmobj.name);
			if (query.get('pds') == '%')
				query.set('pds', pdset.name);

			G_dt1 = new Date();
			query.post(self, noProcess, async, process);
		}

		query = null;
	}

	function attr(element, name)
	{
		return element.getAttribute(name);
	}

	function canPerformAction(action)
	{
		switch (action)
		{
			case 'logout':
				return true;
		}

		var afm = self.activeForm;
		if ((afm == null) && ((!utils.isEmpty(action)) || (action == raClickMenuTree)))
			return true;
		 
		if ((afm != null) && (afm.modal) && (afm.modal.toLowerCase() == 'true'))
			return false;

		return true; 
	}

	function performAction(action)
	{
		if (_disposed)
			return;

		if (action.startsWith('Nav'))
		{
			if ((self.activeForm != null) && (self.activeForm.navigateDataset))
				self.activeForm.navigateDataset(action);
			return;
		}

		switch (action)
		{
			case 'rebuild':
			case 'refresh':
				if ((self.activeForm != null) && (self.activeForm.refreshData))
					self.activeForm.refreshData();
				break;

			case 'filter_on':
				setFilter(true);
				break;

			case 'filter_off':
				setFilter(false);
				break;

			case 'logout':
				logout();
				break;

			case 'sortdlg':
				setSorting();
				break;

			case 'finddlg':
				findDialog();
				break;

			case 'save':
				if ((self.activeForm != null) && (self.activeForm.saveData))
					self.activeForm.saveData();
				break;

			case 'printdlg':
				reportDialog();
				break;
				
		}
	}


	function process(data, noSplashHide)
	{
		if (_disposed)
			return;

		var commands, i,
		    ex = null,
		    commName = 'comm_',
		    commElem = null;
    
		try
		{
			i = 0;
			while ($(commName + i.toString()) != null)
				i++;

			commName += i.toString();
			commElem = getDocument().createElement('div');
			commElem.id = commName;

			commElem.innerHTML = '<qi:user>' + data + '</qi:user>';
			commands = commElem.firstChild.getElementsByTagName("user");
		}
		catch (e) { ex = e; }
		finally
		{
			if (!utils.parseBool(noSplashHide))
				splash(false);
		}

		if (ex != null)
			throw ex;

		if ((commands == null) || (commands.length == 0))
			return;

		var tab, parent, pos, command, object = null;
		for (var i = 0; i < commands.length; i++)
		{
			command = commands[i];

			if (attr(command, "parent") == null)
			{
				tab    = null;
				parent = "";
			}
			else
			{
				pos    = attr(command, "parent").indexOf(scColon);
				tab    = pos == -1 ? null : attr(command, "parent").substring(pos + 1);
				parent = pos == -1 ? attr(command, "parent") : attr(command, "parent").substring(0, pos);
			}

			var name = attr(command, "name");
			var className = command.className;
			object = null;

			switch (attr(command, "cmd"))
			{
				case "add" :
					switch (className)
					{
						case "button" :
							object = new JButton(self, parent, name, attr(command, "caption"), attr(command, "enabled"), attr(command, "rect"), attr(command, "action"), attr(command, "flags"), tab, attr(command, "tabstop"), attr(command, "tabindex"), self.getObject(attr(command, "dataset")), attr(command, "field"));
							break;
						case "btnMenuItem":
							object = self.getObject(parent).addMenuItem(self, parent, name, attr(command, "caption"));
							break;
						case "checkgroup" :
							object = new JCheckGroup(self, parent, name, attr(command, "caption"), self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "paintCaption"), attr(command, "paintRect"), attr(command, "rect"), attr(command, "columns"), tab);
							break;
						case "dataset" :
							object = new JDataset(self, parent, name, attr(command, "key"), attr(command, "sort"), attr(command, "flags"), attr(command, "masterDS"), attr(command, "masterFields"), attr(command, "dsid"), attr(command, "dspf"));
							break;
						case "edit" :
							object = new JEdit(self, parent, name, self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "rect"), attr(command, "type"), tab, attr(command, "tabstop"), attr(command, "tabindex"), attr(command, "richtext"), attr(command, "flags"));
							break;
						case "enumpicker" :
							object = new JEnumPicker(self, parent, name, self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "rect"), tab, attr(command, "tabstop"), attr(command, "tabindex"));
							break;
						case "field" :
							self.getObject(parent).addField(new JField(name, attr(command, "caption"), attr(command, "type"), attr(command, "items"), attr(command, "flags")));
							break;
						case "filter" :
							object = new JFilter(self, parent, name, attr(command, "caption"), self.getObject(attr(command, "dataset")), self.getObject(attr(command, "default")));
							break;
						case "filterdialog" :
							object = new JFilterDialog(self, parent, name, attr(command, "caption"), attr(command, "action"), attr(command, "method"), attr(command, "rect"));
							break;
						case "form" :
							object = new JForm(self, parent, name, attr(command, "caption"), attr(command, "action"), attr(command, "method"), attr(command, "rect"), attr(command, "flags"), attr(command, "previous"), attr(command, "reports"), attr(command, "modal"));
							self.onformcreated.raise(self, object);
							break;
						case "grid" :
							object = new JGrid(self, parent, name, self.getObject(attr(command, "dataset")), attr(command, "columns"), attr(command, "widths"), attr(command, "rect"), attr(command, "flags"), attr(command, "treefields"), tab);
							break;
						case "chart" :
							object = new JChart(self, parent, name, self.getObject(attr(command, "dataset")), attr(command, "rect"), tab);
							break;
						case "checkbox" :
							object = new JCheckbox(self, parent, name, self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "rect"), tab);
							break;
						case "tscheckbox" :
							object = new JTriStateCheckBox(self, parent, name, attr(command, "caption"), self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "rect"), tab, attr(command, "tabstop"), attr(command, "tabindex"), attr(command, "align"), attr(command, "state"));
							break;
						case "info" :
							self.getObject(parent).setInfo(attr(command, "records"), attr(command, "size"), attr(command, "page"));
							break;
						case "image" :
							object = new JImage(self, parent, name, self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "rect"), attr(command, "flags"), tab);
							break;
						case "label" :
							object = new JLabel(self, parent, name, self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "caption"), attr(command, "alignment"), attr(command, "rect"), tab);
							break;
						case "messagedialog" :
							alert(attr(command, "message"));
							break;
						case "projection" :
							object = new JProjection(self, parent, name, attr(command, "width"), attr(command, "height"), attr(command, "left"), attr(command, "top"), attr(command, "zoomEnabled"), attr(command, "zoom"), attr(command, "tZoomEnabled"), attr(command, "tZoom"), attr(command, "rect"), tab);
							break;
						case "radiogroup" :
						    object = new JRadioGroup(self, parent, name, attr(command, "caption"), self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "paintCaption"), attr(command, "paintRect"), attr(command, "rect"), attr(command, "columns"), tab);
							break;
						case "record" :
							self.getObject(parent).loadRecord(attr(command, "cmd"), attr(command, "key"), attr(command, "buffer"), attr(command, "status"), attr(command, "flags"), attr(command, "tvflags"), attr(command, "tvlevel"), attr(command, "tvindex"), attr(command, "goto"), attr(command, "rflags"), attr(command, "fflags"));
							break;
						case "scrollbox" :
							object = new JScrollBox(self, parent, name, attr(command, "rect"), tab);
							break;
						case "setpicker" :
							object = new JSetPicker(self, parent, name, self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "rect"), tab, attr(command, "tabstop"), attr(command, "tabindex"));
							break;
						case "tabfolder" :
							object = new JTabFolder(self, parent, name, attr(command, "tabs"), attr(command, "activetab"), attr(command, "rect"), tab);
							break;
						case "timepicker" :
							object = new JCalendar(self, parent, name, self.getObject(attr(command, "dataset")), attr(command, "field"), attr(command, "rect"), attr(command, "type"), tab, attr(command, "tabstop"), attr(command, "tabindex"));
							break;
						case "toolbar":
							object = new JToolbar(self, parent, name);
							break;
						case "toolbutton":
							object = self.getObject(parent).addButton(self, parent, name, attr(command, "image"), attr(command, "caption"), attr(command, "hint"), attr(command, "actiontarget"), attr(command, "enabled"));
							break;
						case "treenode" :
							object = new JTreeNode2(self, parent, attr(command, "type"), name, attr(command, "caption"), attr(command, "expanded"), attr(command, "loaded"));
							break;
						case "treeview" :
							object = new JTreeView2(self, parent, name, attr(command, "rect"), tab);
							break;
						case "newPassword" :
							object = new JPasswordChangeDialog(self, parent, name, attr(command, "caption"), attr(command, "loginCode"), attr(command, "minLength"), '0;0;400;150');
							break;
					}

					if (object != null)
					{
						self.registerObject(name, object);

						if (parent != "")
						{
							var obj = self.getObject(parent);
							if ((obj) && (obj.addControl))
								obj.addControl(object);
						}
					}

					break;

				case "insert" :
				case "insertLevel" :
					if (className == "record")
					{
						self.getObject(parent).loadRecord(attr(command, "cmd"), attr(command, "key"), attr(command, "buffer"), attr(command, "status"), attr(command, "flags"), attr(command, "tvflags"), attr(command, "tvlevel"), attr(command, "tvindex"), attr(command, "goto"), attr(command, "rflags"), attr(command, "fflags"));
					}
					break;

				case "clear" :
					self.getObject(name).clear(true);
					break;

				case "modify":
				{
					switch (className)
					{
						case "record" :
							self.getObject(parent).loadRecord(attr(command, "cmd"), attr(command, "key"), attr(command, "buffer"), attr(command, "status"), attr(command, "flags"), attr(command, "tvflags"), attr(command, "tvlevel"), attr(command, "tvindex"), attr(command, "goto"), attr(command, "rflags"), attr(command, "fflags"));
							break;
						default :
							var item;
							var name = attr(command, "name");
							if ((name == '') || (name == 'app') || (name == 'application'))
								item = self;
							else
								item = self.getObject(name);

							var prop = attr(command, "property");
							var propValue = attr(command, "value");

							if (item != null)
							{
								if (prop != "")
								{
									if (utils.inList(attr(command, "value"), "false", "true"))
										propValue = utils.parseBool(attr(command, "value"));

									if (item['set_' + prop] != null)
										item['set_' + prop].call(item, propValue);
									else
									if (prop != null)
										item[prop] = attr(command, "value");

								}

								if (attr(command, "rerender") == "true")
									item.render();

								if (attr(command, "executeafter") != null)
								{
									eval("item." + attr(command, "executeafter"));
								}

							}
							break;
					}
					break;
				}

				case "set":
					self[className] = attr(command, "value");
					break;

				case "refresh" :
					self.refresh(attr(command, "target"));
					break;

				case "remove" :
					if (className == "record")
					{
						self.getObject(parent).loadRecord(attr(command, "cmd"), attr(command, "key"), attr(command, "buffer"), attr(command, "status"), attr(command, "flags"), attr(command, "tvflags"), attr(command, "tvlevel"), attr(command, "tvindex"), attr(command, "goto"), attr(command, "rflags"), attr(command, "fflags"));
					}
					else
					{
						var obj = self.getObject(name);
						if (obj != null)
						{
							if (obj.dispose)
								obj.dispose();

							self.unregisterObject(name);
						}
					}
					break;

				case "error" :
					var msg = unescape(command.getAttribute("message"));
					showError(msg);
					break;

				case "nosession" :
					var sessionId = escape(attr(command, "sessionId"));
					if ((!_cleaning) && (!_loggingOut) && ((sessionId == self.session) || (utils.isEmpty(sessionId))))
					{
						if (_pingTimer != null)
							window.clearTimeout(_pingTimer);

						_cleanup();

						if ($(idLoginForm))
							$(idLoginForm).style.display = 'none';
						$(idAppForm).style.display = 'none';
						$(idNoSession).style.display = 'block';
					}
					break;
					
			}
		}

		if (commElem != null)
		{
			if (commElem.parentNode != null)
				commElem.parentNode.removeChild(commElem);
			else
			try
			{
					getDocument().removeChild(commElem);
			}
			catch (e)
			{
				delete commElem;
			}
		}

		var rPart = $(idRightPane);
		if ((rPart != null) && (rPart.scrollTop > 0))
			rPart.scrollTop = 0;

	}
  
	function refresh(target)
	{
		if (target == idTree)
		{
			var html = new FastString();
			var tvwm = getObject('tvwm1');
			if (tvwm != null)
			{
				tvwm.render(html);
				$(idTree).innerHTML = html.toString();
				self.load(target);
			}
		}
		else
		if (((utils.isEmpty(target)) || (target == idMain)) && (self.activeForm != null) && (!self.activeForm.isRendered()))
		{
			var html = new FastString();
			self.activeForm.render(html)

			var tempDiv = self.getTempDiv();
			tempDiv.innerHTML = html.toString();
			$(idMain).appendChild(tempDiv.firstChild);

			self.load(target);
		}

		if ((self.activeForm != null) && (self.activeForm.checkSaveButton))
			self.activeForm.checkSaveButton();
	}

	function load(target)
	{
		if (target == idTree)
		{
			getObject('tvwm1').load();
		}
		else
		if ((target == null) || (target == '') || (target == idMain))
			self.activeForm.load();
	}

	function showError(msg)
	{
		var type = 0, text = '', msgId = '';
		var splitted = msg.split('\n');
		
		for (var i = 0; i < splitted.length; i++)
		{
			var s = splitted[i];
			if (s.startsWith('Type='))
				type = parseInt(s.substr(s.indexOf('Type=') + 5).trim());
			else
			if (s.startsWith('Text='))
				text = s.substr(s.indexOf('Text=') + 5).trimEnd();
			else
			if (s.startsWith('MsgId='))
				msgId = s.substr(s.indexOf('MsgId=') + 6).trim();
			else
				text += '\n' + s;
		}

		if (msgId != '')
		{
			if (!utils.isEmpty(sysMessages[msgId]))
				text = sysMessages[msgId];
			if (sysMsgTypes[msgId] != null)
				type = sysMsgTypes[msgId];
		} 

		if (text != "")
		{
			var typeText;
			switch (type)
			{
				case mtInformation :
					typeText = self.localize('capInformation', 'Information');
					break;
				case mtWarning:
					typeText = self.localize('capWarning', 'Warning');
					break;
				case mtError:
					typeText = self.localize('capError', 'Error');
					break;
				case mtQuestion:
					typeText = self.localize('capQuestion', 'Question');
					break;
				default:
					typeText = 'Problem ' + type;
					break;
			}

			alert(typeText + ":\n" + text);
		}
	}

	function setSplashInfo(message)
	{
/*
		var fun = function()
		{
			return function() { $(idSplash + '_info').innerHTML = message };
		}

		window.setTimeout(fun, 1);
*/

		$(idSplash + '_info').innerHTML = message;
		if ((message == null) || (message == ''))
			$(idSplash + '_info').style.display = 'none';
		else
			$(idSplash + '_info').style.display = 'block';

	}

	function getSplashInfo()
	{
		return $(idSplash + '_info').innerHTML;
	}

	function splash(show)
	{
		if (show)
		{
			_splashCnt++;
			$(idSplash).style.display = 'block';
		}
		else
		{
			if (_splashCnt > 0)
				_splashCnt--;

			if (_splashCnt == 0)
				$(idSplash).style.display = 'none';
			setSplashInfo('loading...');
		}
	}

	function isCleaning()
	{
		return _cleaning;
	}

	function debugAdd(msg)
	{
		if (! _debugEnabled)
			return;

		_debugTiming.append(msg);
	}

	function debugClear()
	{
		_debugTiming.clear();
	}

	function debugShow(clear)
	{
		var str = _debugTiming.toString();
		if (str == '')
			return;

		alert(str);

		if (clear)
			_debugTiming.clear();
	}

	function dispose(async)
	{
		if ((_disposed) || (_disposing))
			return;

		_disposing = true;

		if (! utils.isEmpty(self.session))
			logout(async);

		_forms = null;
		_objects = null;
		_localized.dispose();
		_localized = null;
		_appDS.dispose();
		_appDS = null;
		_debugTiming = null;
		_popups = null;

		self.onlogin.dispose();
		self.onlogin = null;
		self.onbeforelogout.dispose();
		self.onbeforelogout = null;
		
		RemoveEventHandler();

		_disposed = true;
	}
}




function Postback(action)
{
	var self = this,
	    _owner,
	    _noProcess,
	    _async,
	    _resultFunc,
	    _errFunc,
	    _cleaning,
	    _noSplash = false;
	    _result = null;

	this.action = action;
	this.items  = new Array();

	this.get      = get;
	this.set      = set;
	this.append   = append;
	this.getQuery = getQuery;
	this.post     = post;
	this.toString = toString;

	function get(item)
	{
		return ( self.items[item] );
	}
  
	function set(item, value)
	{
		if (self.items[item] == null)
		{
			self.items[item] = utils.coalesce(value, "");
			self.items.length++;
		}
		else
		{
			self.items[item] = utils.coalesce(value, "");
		}
	}

	function append(query)
	{
		if (query == null)
			return;

		if (query.constructor == Postback)
		{
			for (var i in query.items)
			{
				if (Array.prototype[i] != null)
					continue;

				self.set(i, query.items[i]);
			}
		}
		else
		if ((query.constructor == String) || (query.constructor == Array))
		{
			if (query.constructor == String)
				query = query.split(scAmpersand);

			for (var i = 0; i < query.length; i++)
			{
				var item = query[i].split(scEquals);
				self.set(item[0], item[1]);
			}
		}
	}
  
	function getQuery()
	{
		var query = new Array();
  
		for (var item in self.items)
		{
			if (Array.prototype[item] != null)
				continue;

			query[query.length++] = (item + "=" + self.items[item]);
		}

		return (query.join("&"));
	}

	function post(owner, noProcess, async, resultFunc, errFunc)
	{
		owner.splash(true);

/*
		if (async)
			_noSplash = true;
		else
		{
			_noSplash = false;
			owner.splash(true);
		}
*/
		if (!utils.inList(self.action, raPost, raOperateDataset))
			async = true;

		if (resultFunc == null)
			throw "resultFunc must be defined in Postback.post call."

		_owner = owner;
		_noProcess = noProcess;
		_async = async;
		_resultFunc = resultFunc;
		_errFunc = errFunc;
		_cleaning = owner.isCleaning();

		if (async)
		{
			owner.makeAjaxCall("post", owner.cgiPath(), getQuery(), null, true, asyncResultFunc);
		}
		else
		{
			var result = owner.makeAjaxCall("post", owner.cgiPath(), getQuery(), null, false);

			if (! _noProcess)
				resultFunc(result, true);
//			else
//				owner.splash(false);

			owner.splash(false);
		}
	}

	function asyncResultFunc(resultStatus, result)
	{
		if (_noProcess)
			_owner.splash(false);

		if ((resultStatus == 200) || (resultStatus == 201))
		{
			if (!_noProcess)
			{
				_result = result;
				_owner.setSplashInfo('processing...');
				window.setTimeout(_processResult, 1);
			}
		}
		else
		if (_errFunc != null)
			_errFunc(resultStatus, result);
	}

	function _processResult()
	{
		if (_resultFunc != null)
			_resultFunc(_result, _noSplash);
	}

	function toString()
	{
		return getQuery();
	}
}

function __onUnload()
{
	utils.detachEvent(window, 'unload', __onUnload);

	if ((app != null) && (app.dispose))
		app.dispose(true);
	app = null;
	window.ICApp = null;
}

function start()
{
}

var app = new JApplication(document);
utils.attachEvent(window, 'unload', __onUnload);
window.ICApp = app;

if (typeof(loadNextScript) != 'undefined')
	loadNextScript();
